﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.ServiceModel.Web;
using COFE.Core;
using COFE.IO;
using COFE.Web.Json;

namespace COFE.Web.Services
{
    /// <summary>
    /// Frontend class for encoding/decoding Xml and Json.
    /// </summary>
    public static class EncodeObjectUtils
    {
        public enum EncodeFormat { Xml, Json };

        #region Xml functions
        private static Stream encodeXml<T>(T obj)
            where T : ISupportXml
        {
            WebOperationContext.Current.OutgoingResponse.ContentType = MIMETypeExtension.GetMIMEType(MediaType.Xml);         
            return XmlStreamUtils.ToXmlStream(obj);            
        }

        private static T decodeXml<T>(IUserProfile profile, Stream stream)
        {
            Type type = typeof(T);
            if (type == typeof(Entry))
                return (T)(object)XmlStreamUtils.EntryFromXmlStream(profile, stream);
            else if (type == typeof(EntryType))
                return (T)(object)XmlStreamUtils.EntryTypeFromXmlStream(profile, stream);
            else if (type == typeof(EntryList))
                return (T)(object)XmlStreamUtils.EntryListFromXmlStream(profile, stream);
            else throw new ArgumentException();
        }

        #endregion

        #region Json functions

        private static Stream encodeJson<T>(T obj)
            where T : ISupportXml
        {
            return JsonSerializationUtils.ToJsonStream(obj.ToXml(true));
        }

        //private static T decodeJson<T>(IUserProfile manager, Stream stream)
        //{

        //}
        #endregion

        /// <summary>
        /// Encode a supported object (Entry, EntryList, Search, MetadataList) to the specified fromat.
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="format"></param>
        /// <returns></returns>
        public static Stream EncodeObject<T>(T obj, EncodeFormat format)
            where T : ISupportXml
        {
            if (format == EncodeFormat.Xml)
            {
                WebOperationContext.Current.OutgoingResponse.ContentType = MIMETypeExtension.GetMIMEType(MediaType.Xml);
                return encodeXml(obj);
            }
            else
            {
                WebOperationContext.Current.OutgoingResponse.ContentType = MIMETypeExtension.GetMIMEType(MediaType.Json);
                return encodeJson(obj);
            }
        }

        /// <summary>
        /// Encode a supported object (Entry, EntryList, Search, MetadataList) to xml, or json if the property json equals "true".
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="json"></param>
        /// <returns></returns>
        public static Stream EncodeObject<T>(T obj, string json)
            where T : ISupportXml
        {
            EncodeObjectUtils.EncodeFormat fmt = json != null && json.ToLower() == "true" ?
                        EncodeObjectUtils.EncodeFormat.Json : EncodeObjectUtils.EncodeFormat.Xml;
            return EncodeObject(obj, fmt);
        }


        /// <summary>
        /// Decode a supported object (Entry, EntryList, Search) from a stream.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="manager"></param>
        /// <param name="stream"></param>
        /// <param name="format"></param>
        /// <returns></returns>
        public static T DecodeObject<T>(IUserProfile profile, Stream stream, EncodeFormat format)
        {
            if (format == EncodeFormat.Xml)
            {
                return decodeXml<T>(profile, stream);
            }
            else
            {
                string json = null;
                using (var sr = new StreamReader(stream))
                    json = sr.ReadToEnd();

                if (typeof(T) == typeof(MetadataList))
                    return DecodeObject<T>(profile, JsonSerializationUtils.ToXmlStream(XNames.Metadata, json), EncodeFormat.Xml);
                if (typeof(T) == typeof(Entry))
                    return DecodeObject<T>(profile, JsonSerializationUtils.ToXmlStream(XNames.Entry, json), EncodeFormat.Xml);
                if (typeof(T) == typeof(EntryType))
                    return DecodeObject<T>(profile, JsonSerializationUtils.ToXmlStream(XNames.EntryType, json), EncodeFormat.Xml);
                if (typeof(T) == typeof(EntryList))
                    return DecodeObject<T>(profile, JsonSerializationUtils.ToXmlStream(XNames.List, json), EncodeFormat.Xml);

                throw new NotSupportedException(format.ToString());
            }
        }

        public static T DecodeObject<T>(IUserProfile profile, Stream stream, string json)
        {
            EncodeObjectUtils.EncodeFormat fmt = json != null && json.ToLower() == "true" ?
                        EncodeObjectUtils.EncodeFormat.Json : EncodeObjectUtils.EncodeFormat.Xml;
            return DecodeObject<T>(profile, stream, fmt);
        }


    }
}